home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 3_0 / MACBINAR / MBPUT.C < prev   
C/C++ Source or Header  |  1988-06-14  |  10KB  |  516 lines

  1. /*
  2. Date: Tue, 12 Apr 88 22:12:06 EDT
  3. From: singer@harvard.harvard.edu (Jon Hueras)
  4. Subject: mbput.c
  5.  
  6. The comments below notwithstanding, this program does not do
  7. Macterminal 1.1 style transfers, but rather MacBinary style
  8. transfers. It still uses XModem transport protocol, but
  9. this version has been modified to recognize and use CRCs
  10. instead of 8-bit checksums when appropriate.
  11.  
  12. This program is supplied as-is, which is to say that this
  13. is what I have been using for the past two years, ever
  14. since I stopped using MacTerminal and started using Red
  15. Ryder. I have used it successfully with Red Ryder versions
  16. 9.2 through 10.2 inclusive, and possibly even earlier versions
  17. than that. I have no knowledge of its performance with any
  18. other terminal emulation software.
  19.  
  20.     Jon Hueras
  21.     Symantec/THINK Technologies
  22.     singer@endor.harvard.edu
  23.  
  24. */
  25.  
  26. /*
  27.  
  28. Here is the source for the current incarnation of macput . . . .
  29. It is compatible with the 1.1 Release version of MacTerminal,
  30. though in case you still need to use the -0.15X version, there's
  31. the "-o" option to provide compatibility.  Versions 0.5 and 0.9
  32. have a bug in the record checksum calculation which will break
  33. file transfers, so 1.1 is recommended.
  34.  
  35. Please pass any improvements/bug fixes on to me, and
  36. if you know of any good protocols for use on a flow-controlled
  37. line, let me know.
  38.  
  39.     Dave Johnson
  40.     ddj%brown@csnet-relay.arpa
  41.     Brown University Computer Science
  42.  
  43. */
  44. #include <stdio.h>
  45. #include <signal.h>
  46. #include <setjmp.h>
  47. #include <sgtty.h>
  48. #include <time.h>
  49. #include <sys/types.h>
  50. #include <sys/stat.h>
  51. #include <sys/timeb.h>
  52.  
  53. #define RECORDBYTES 132
  54. #define DATABYTES 128
  55. #define NAMEBYTES 63
  56.  
  57. #define RETRIES 10
  58. #define ACKTIMO 10
  59.  
  60. #define MAXRECNO 0xff
  61. #define BYTEMASK 0xff
  62.  
  63. #define TMO -1
  64. #define DUP '\000'
  65. #define SOH '\001'
  66. #define EOT '\004'
  67. #define ACK '\006'
  68. #define NAK '\025'
  69. #define CAN '\030'
  70. #define EEF '\032'
  71. #define ESC '\033'
  72.  
  73. #define H_NLENOFF 1
  74. #define H_NAMEOFF 2
  75. /* 65 <-> 80 is the FInfo structure */
  76. #define H_TYPEOFF 65
  77. #define H_AUTHOFF 69
  78.  
  79. #define H_LOCKOFF 81
  80. #define H_DLENOFF 83
  81. #define H_RLENOFF 87
  82. #define H_CTIMOFF 91
  83. #define H_MTIMOFF 95
  84.  
  85. #define H_OLD_DLENOFF 81
  86. #define H_OLD_RLENOFF 85
  87.  
  88. #define TEXT 0
  89. #define DATA 1
  90. #define RSRC 2
  91. #define FULL 3
  92.  
  93. int mode, txtmode;
  94.  
  95. struct macheader {
  96.     char m_name[NAMEBYTES+1];
  97.     char m_type[4];
  98.     char m_author[4];
  99.     long m_datalen;
  100.     long m_rsrclen;
  101.     long m_createtime;
  102.     long m_modifytime;
  103. } mh;
  104.  
  105. struct filenames {
  106.     char f_info[256];
  107.     char f_data[256];
  108.     char f_rsrc[256];
  109. } files;
  110.  
  111. int recno, crc;
  112. char buf[DATABYTES];
  113.  
  114. /*
  115.  * macput -- send file to macintosh using xmodem protocol
  116.  * Dave Johnson, Brown University Computer Science
  117.  *
  118.  * (c) 1984 Brown University 
  119.  * may be used but not sold without permission
  120.  *
  121.  * created ddj 6/17/84 
  122.  * revised ddj 7/16/84 -- protocol changes for MacTerminal Beta Version 0.5X
  123.  * revised ddj 7/31/84 -- pre-4.2 signal bugs fixed in timedout()
  124.  * revised ddj 7/31/84 -- moved forge_info() call ahead of send_sync()
  125.  * revised ddj 11/6/84 -- added sleep(5) after send_sync to give mac time to
  126.  *                          turn off xon mode, set up sio chip, and put up
  127.  *                        progress indicator
  128.  * revised jfh 6/24/86 -- modified to do MacBinary transfers, rather than
  129.  *                        MacTerminal's mac-to-mac style transfers, and
  130.  *                        added CRC handling to the XModem layer. Also
  131.  *                        enabled the <ESC>B auto-receive feature. Changed
  132.  *                        name to mbput ('mb' for MacBinary) to avoid
  133.  *                        confusion with the original macput.
  134.  */
  135.  
  136. char usage[] =
  137.     "usage: \"mbput [-rdu] [-t type] [-a author] [-n name] filename\"\n";
  138.  
  139. main(ac, av)
  140. char **av;
  141. {
  142.     int n;
  143.     char *filename;
  144.  
  145.     if (ac == 1) {
  146.         fprintf(stderr, usage);
  147.         exit(1);
  148.     }
  149.  
  150.     mode = FULL;
  151.     ac--; av++;
  152.     while (ac) {
  153.         if (av[0][0] == '-') {
  154.             switch (av[0][1]) {
  155.             case 'r':
  156.                 mode = RSRC;
  157.                 strncpy(mh.m_type, "????", 4);
  158.                 strncpy(mh.m_author, "????", 4);
  159.                 break;
  160.             case 'u':
  161.                 mode = TEXT;
  162.                 strncpy(mh.m_type, "TEXT", 4);
  163.                 strncpy(mh.m_author, "PEDT", 4);
  164.                 break;
  165.             case 'd':
  166.                 mode = DATA;
  167.                 strncpy(mh.m_type, "????", 4);
  168.                 strncpy(mh.m_author, "????", 4);
  169.                 break;
  170.             case 'n':
  171.                 if (ac > 1) {
  172.                     ac--; av++;
  173.                     n = strlen(av[0]);
  174.                     if (n > NAMEBYTES) n = NAMEBYTES;
  175.                     strncpy(mh.m_name, av[0], n);
  176.                     mh.m_name[n] = '\0';
  177.                     break;
  178.                 }
  179.                 else goto bad_usage;
  180.             case 't':
  181.                 if (ac > 1) {
  182.                     ac--; av++;
  183.                     strncpy(mh.m_type, av[0], 4);
  184.                     break;
  185.                 }
  186.                 else goto bad_usage;
  187.             case 'a':
  188.                 if (ac > 1) {
  189.                     ac--; av++;
  190.                     strncpy(mh.m_author, av[0], 4);
  191.                     break;
  192.                 }
  193.                 else goto bad_usage;
  194.             default:
  195. bad_usage:
  196.                 fprintf(stderr, usage);
  197.                 exit(1);
  198.             }
  199.         }
  200.         else {
  201.             filename = av[0];
  202.         }
  203.         ac--; av++;
  204.     }
  205.  
  206.     setup_tty();
  207.     find_files(filename, mode);
  208.     if (mode != FULL)
  209.         forge_info();
  210.  
  211.     if (send_sync()) {
  212.         recno = 1;
  213.         txtmode = 0;
  214.         send_file(files.f_info, 1);
  215.  
  216.         if (mode != FULL)
  217.             unlink(files.f_info);
  218.  
  219.         if (mode == TEXT) txtmode++;
  220.         send_file(files.f_data, 1);
  221.  
  222.         txtmode = 0;
  223.         send_file(files.f_rsrc, 0);
  224.     }
  225.     reset_tty();
  226. }
  227.  
  228. find_files(filename, mode)
  229. char *filename;
  230. {
  231.     int n, tdiff;
  232.     struct tm *tp;
  233.     struct timeb tbuf;
  234.     struct stat stbuf;
  235.  
  236.     sprintf(files.f_data, "%s.data", filename);
  237.     sprintf(files.f_rsrc, "%s.rsrc", filename);
  238.  
  239.     if (mode == FULL) {
  240.         sprintf(files.f_info, "%s.info", filename);
  241.         if (stat(files.f_info, &stbuf) != 0) {
  242.             perror(files.f_info);
  243.             cleanup(-1);
  244.         }
  245.         return;
  246.     }
  247.     else {
  248.         strcpy(files.f_info, "#machdrXXXXXX");
  249.         mktemp(files.f_info);
  250.     }
  251.  
  252.     if (mode == RSRC) {
  253.         strcpy(files.f_data, "/dev/null");
  254.         if (stat(files.f_rsrc, &stbuf) != 0) {
  255.             strcpy(files.f_rsrc, filename);
  256.             if (stat(files.f_rsrc, &stbuf) != 0) {
  257.                 perror(files.f_rsrc);
  258.                 cleanup(-1);
  259.             }
  260.         }
  261.         mh.m_datalen = 0;
  262.         mh.m_rsrclen = stbuf.st_size;
  263.     }
  264.     else {
  265.         strcpy(files.f_rsrc, "/dev/null");
  266.         if (stat(files.f_data, &stbuf) != 0) {
  267.             sprintf(files.f_data, "%s.text", filename);
  268.             if (stat(files.f_data, &stbuf) != 0) {
  269.                 strcpy(files.f_data, filename);
  270.                 if (stat(files.f_data, &stbuf) != 0) {
  271.                     perror(files.f_data);
  272.                     cleanup(-1);
  273.                 }
  274.             }
  275.         }
  276.         mh.m_datalen = stbuf.st_size;
  277.         mh.m_rsrclen = 0;
  278.     }
  279.  
  280.     if (mh.m_name[0] == '\0') {
  281.         n = strlen(filename);
  282.         if (n > NAMEBYTES) n = NAMEBYTES;
  283.         strncpy(mh.m_name, filename, n);
  284.         mh.m_name[n] = '\0';
  285.     }
  286. }
  287.  
  288. forge_info()
  289. {
  290.     int n;
  291.     char *np;
  292.     FILE *fp;
  293.  
  294.     for (np = mh.m_name; *np; np++)
  295.         if (*np == '_') *np = ' ';
  296.  
  297.     buf[H_NLENOFF] = n = np - mh.m_name;
  298.     strncpy(buf + H_NAMEOFF, mh.m_name, n);
  299.     strncpy(buf + H_TYPEOFF, mh.m_type, 4);
  300.     strncpy(buf + H_AUTHOFF, mh.m_author, 4);
  301.     put4(buf + H_DLENOFF, mh.m_datalen);
  302.     put4(buf + H_RLENOFF, mh.m_rsrclen);
  303.     put4(buf + H_CTIMOFF, mh.m_createtime);
  304.     put4(buf + H_MTIMOFF, mh.m_modifytime);
  305.     fp = fopen(files.f_info, "w");
  306.     if (fp == NULL) {
  307.         perror("temp file");
  308.         cleanup(-1);
  309.     }
  310.     fwrite(buf, 1, DATABYTES, fp);
  311.     fclose(fp);
  312. }
  313.  
  314. send_sync()
  315.     {
  316.         int c;
  317.         
  318.         tputc(ESC);
  319.         tputc('b');
  320.  
  321.         for (;;) {
  322.  
  323.             if ((c = tgetc(ACKTIMO)) == TMO)
  324.                 return(0);
  325.  
  326.             if (c == NAK)
  327.                 return(1);
  328.  
  329.             if (c == 'C') {
  330.                 crc++;
  331.                 return(1);
  332.             }
  333.         }
  334.     }
  335.  
  336. send_file(fname, more)
  337. char *fname;
  338. int more;
  339. {
  340.     register int status, i, n;
  341.     FILE *inf;
  342.  
  343.     inf = fopen(fname, "r");
  344.     if (inf == NULL) {
  345.         perror(fname);
  346.         cleanup(-1);
  347.     }
  348.     for (;;) {
  349.         n = fread(buf, 1, DATABYTES, inf);
  350.         if (n > 0) {
  351.             for (i = 0; i < RETRIES; i++) {
  352.                 send_rec(buf, DATABYTES);
  353.                 while ((status = tgetc(ACKTIMO)) != ACK && status != NAK && status != CAN);
  354.                 if (status != NAK)
  355.                     break;
  356.             } 
  357.             if (status != ACK) {
  358.                 if (status != CAN)
  359.                     while ((status = tgetc(ACKTIMO)) != CAN);
  360.                 fclose(inf);
  361.                 cleanup(-1);
  362.                 /* NOTREACHED */
  363.             }
  364.         }
  365.         if (n < DATABYTES) {
  366.             if (!more) {
  367.                 tputc(EOT);
  368.                 tgetc(ACKTIMO);
  369.             }
  370.             return;
  371.         }
  372.         recno++;
  373.         recno &= MAXRECNO;
  374.     }
  375. }
  376.  
  377. send_rec(buf, recsize)
  378. char buf[];
  379. int recsize;
  380. {
  381.     int i, cksum;
  382.     char *bp;
  383.  
  384.     if (txtmode || !crc) {
  385.         cksum = 0;
  386.         bp = buf;
  387.         for (i = 0; i < recsize; i++, bp++) {
  388.             if (txtmode && *bp == '\n')
  389.                 *bp = '\r';
  390.             cksum += *bp;
  391.         }
  392.     }
  393.  
  394.     if (crc)
  395.         cksum = calcrc(buf, recsize);
  396.  
  397.     tputc(SOH);
  398.     tputc((char) recno);
  399.     tputc((char) (MAXRECNO - recno));
  400.     tputrec(buf, recsize);
  401.     
  402.     if (crc) {
  403.         tputc((char) (cksum >> 8));
  404.         tputc((char) cksum);
  405.     } else
  406.         tputc((char) cksum);
  407. }
  408.  
  409. static int ttyfd;
  410. static FILE *ttyf;
  411. static jmp_buf timobuf;
  412.  
  413. tgetc(timeout)
  414. int timeout;
  415. {
  416.     int c;
  417.  
  418.     if (setjmp(timobuf))
  419.         return TMO;
  420.  
  421.     alarm(timeout);
  422.     c = getc(ttyf);
  423.     alarm(0);
  424.  
  425.     if (c == -1)    /* probably hung up or logged off */
  426.         return EOT;
  427.     else
  428.         return c & BYTEMASK;
  429. }
  430.  
  431. tputrec(buf, count)
  432. char *buf;
  433. int count;
  434. {
  435.     write(ttyfd, buf, count);
  436. }
  437.  
  438. tputc(c)
  439. char c;
  440. {
  441.     write(ttyfd, &c, 1);
  442. }
  443.  
  444. timedout()
  445. {
  446.     signal(SIGALRM, timedout);    /* for pre-4.2 systems */
  447.     longjmp(timobuf, 1);
  448. }
  449.  
  450. static struct sgttyb otty, ntty;
  451. /* should turn messages off */
  452.  
  453. setup_tty()
  454. {
  455.     int cleanup();
  456.     int timedout();
  457.  
  458.     ttyf = stdin;
  459.     ttyfd = fileno(stdout);
  460.     ioctl(ttyfd, TIOCGETP, &otty);
  461.     signal(SIGHUP, cleanup);
  462.     signal(SIGINT, cleanup);
  463.     signal(SIGQUIT, cleanup);
  464.     signal(SIGTERM, cleanup);
  465.     signal(SIGALRM, timedout);
  466.     ntty = otty;
  467.     ntty.sg_flags = RAW|ANYP;
  468.     ioctl(ttyfd, TIOCSETP, &ntty);
  469. }
  470.  
  471. reset_tty()
  472. {
  473.     if (ttyf != NULL) {
  474.         sleep(5);    /* should wait for output to drain */
  475.         ioctl(ttyfd, TIOCSETP, &otty);
  476.     }
  477. }
  478.  
  479. cleanup(sig)
  480. int sig;
  481. {
  482.     reset_tty();
  483.     exit(sig);
  484. }
  485.  
  486. put4(bp, value)
  487. char *bp;
  488. long value;
  489. {
  490.     register int i, c;
  491.  
  492.     for (i = 0; i < 4; i++) {
  493.         c = (value >> 24) & BYTEMASK;
  494.         value <<= 8;
  495.         *bp++ = c;
  496.     }
  497. }
  498.  
  499. int calcrc(ptr,    count)
  500. char *ptr;
  501. int count;
  502.     {
  503.         int    crc, i;
  504.  
  505.         crc    = 0;
  506.         while (--count >= 0) {
  507.          crc ^= ((int) *ptr++) << 8;
  508.          for (i = 0; i < 8; ++i)
  509.                  if (crc & 0x8000)
  510.              crc = crc <<    1 ^ 0x1021;
  511.                  else
  512.              crc <<= 1;
  513.          }
  514.         return (crc    & 0xFFFF);
  515.     }
  516.